package com.smallkingson.ylib.core.utils;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.Xml;

import com.smallkingson.ylib.core.Yr;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

public class YXmlUtils {

	/**
	 * 将beanList 写到给定的目录里面去
	 * 
	 * @param file
	 * @param list
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalStateException
	 * @throws IOException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> int writeBeanListToXml(File file, List<T> list)
			throws IllegalArgumentException, IllegalStateException,
			IOException, IllegalAccessException, InvocationTargetException {

		int successNum = 0;

		if (list.size() == 0) {
			return successNum;
		}
		// 根元素
		Class beanClass = list.get(0).getClass();
		String beanClassName = list.get(0).getClass().getName();
		String beanName = beanClassName.substring(beanClassName
				.lastIndexOf(".") + 1);

		FileOutputStream out = new FileOutputStream(file.toString() + "/"
				+ beanName + "s.xml");

		XmlSerializer serializer = Xml.newSerializer();

		serializer.setOutput(out, "utf-8");

		serializer.startDocument("utf-8", true);

		serializer.startTag(null, beanName + "s");
		serializer.attribute(null, "WriteUtil", "YXmlUtils");
		for (Object bean : list) {
			serializer.startTag(null, beanName);

			Method[] methods = beanClass.getMethods();

			for (Method method : methods) {
				if (YBeanUtils.isGetMethod(method)) {
					// 获取字段名
					String fieldName = YBeanUtils
							.getFieldNameFromMethod(method);
					serializer.startTag(null, fieldName);
					String value = "null";
					if (method.invoke(bean) != null
							&& !(method.invoke(bean).toString().equals(""))) {
						// get有返回值
						if (method.invoke(bean).getClass() == Date.class) {
							value = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss")
									.format(method.invoke(bean));
						} else {
							value = method.invoke(bean).toString();
						}
					}
					serializer.text(value);
					serializer.endTag(null, fieldName);
				}
			}
			serializer.endTag(null, beanName);
			successNum++;// 每次写成功一个bean 执行
		}
		serializer.endTag(null, beanName + "s");
		serializer.endDocument();
		out.flush();
		out.close();
		return successNum;
	}

	public static String objectToXml(Object object ,String root) {
		ByteArrayOutputStream baos = null;
		try {

			XmlSerializer serializer = Xml.newSerializer();

			 baos = new ByteArrayOutputStream();

			serializer.setOutput(baos , "utf-8");

			serializer.startDocument("utf-8", true);

			serializer.startTag(null, root);

			List<Method> getMethods = YBeanUtils.getGetMethods(object.getClass());

			for (Method method : getMethods) {
				String fieldNameByMethodName = YBeanUtils.getFieldNameByMethodName(method.getName());
				serializer.startTag(null, fieldNameByMethodName);
				Object value = method.invoke(object);
				serializer.text(value==null?"null":value.toString());
				serializer.endTag(null, fieldNameByMethodName);
			}
			serializer.endTag(null, root);
			serializer.endDocument();
			baos.close();
			return baos.toString();
		} catch (Exception e) {
			Yr.logError(e);
		}finally {
			try {
				if (baos!=null) {
				baos.close();
				}
			} catch (IOException e) {
				Yr.logError(e);
			}

		}
		return null;
	}
	/**
	 * 根据给定的文件夹位置 自动解析由YXmlUtils写出的XML
	 * 
	 * @param file
	 * @param BeanClass
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws DOMException
	 * @throws InvocationTargetException
	 * @throws IllegalArgumentException
	 * @throws NumberFormatException
	 * @throws ParseException
	 */
	@SuppressLint("NewApi")
	public static <T> List<T> readXmlToBeanList(File file, Class<T> BeanClass)
			throws ParserConfigurationException, SAXException, IOException,
			InstantiationException, IllegalAccessException,
			NumberFormatException, IllegalArgumentException,
			InvocationTargetException, DOMException, ParseException {

		DocumentBuilderFactory factory = null;
		DocumentBuilder builder = null;
		Document document = null;
		InputStream in = null;
		factory = DocumentBuilderFactory.newInstance();
		builder = factory.newDocumentBuilder();

		String beanClassName = BeanClass.getName();
		String beanName = beanClassName.substring(beanClassName
				.lastIndexOf(".") + 1);
		in = new FileInputStream(file.toString() + "/" + beanName + "s.xml");
		document = builder.parse(in);

		// 找到根Element
		Element root = document.getDocumentElement();

		// 根据set方法的数量开始反射
		Method[] methods = BeanClass.getMethods();

		// 获取bean的数量
		int beanCount = root.getElementsByTagName(beanName).getLength();

		List<T> beans = null;

		if (beanCount > 0) {
			beans = new LinkedList<T>();
			for (int i = 0; i < beanCount; i++) {
				beans.add(BeanClass.newInstance());
			}
		}

		for (Method method : methods) {
			String methodName = method.getName();
			if (YBeanUtils.isSetMethod(method)) {

				String fieldName = YBeanUtils.getFieldNameFromMethod(method);
				Class fieldClass = YBeanUtils.getPropertyType(BeanClass,
						fieldName);

				NodeList nodesList = root.getElementsByTagName(fieldName);
				for (int j = 0; j < nodesList.getLength(); j++) {
					// 赋值
					String content = nodesList.item(j).getTextContent();
					if (content.equals("null") || content == null) {
						continue;
					}
					if (fieldClass == String.class) {
						method.invoke(beans.get(j), content);
					} else if (fieldClass == Integer.class) {
						method.invoke(beans.get(j), Integer.parseInt(content));
					} else if (fieldClass == Float.class) {
						method.invoke(beans.get(j), Float.parseFloat(content));
					} else if (fieldClass == Date.class) {
						// new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss") 根据这个格式
						method.invoke(beans.get(j), new SimpleDateFormat(
								"yyyy年MM月dd日 HH:mm:ss").parse(content));
					} else if (fieldClass == List.class) {
						method.invoke(beans.get(j),
								YCollections.parseList(content));
					}
				}
			}
		}

		return beans;
	}

	/**
	 * 
	 * @param context
	 * @param fileName
	 * @param str
	 * @throws Exception
	 */
	public static void store(Context context, String fileName, String... str)
			throws Exception {

		if (str == null) {
			throw new NullPointerException();
		}
		if (str.length % 2 != 0) {
			throw new Exception("参数不是键值对");
		}
		SharedPreferences sp = context.getSharedPreferences(fileName,
				Context.MODE_PRIVATE);
		Editor editor = sp.edit();
		for (int i = 0; i < str.length; i += 2) {

			editor.putString(str[i], str[i + 1]);

		}
		editor.commit();
	}

	/**
	 * 给我一个对象，我把它用SharedPreferences写到data/data里面
	 * 
	 * @param context
	 * @param bean
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	@SuppressLint("DefaultLocale")
	public static void storeBeanBySP(Context context, Object bean) {
		storeBeanBySP(context, bean, null);
	}

	/**
	 * 给我一个对象，我把它用SharedPreferences写到data/data里面
	 * 
	 * @param context
	 * @param bean
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	@SuppressLint("DefaultLocale")
	public static void storeBeanBySP(Context context, Object bean, Config config) {

		// 健壮性
		if (bean == null) {
			throw new NullPointerException();
		}
		if (context == null) {
			throw new NullPointerException();
		}

		try {
			// 获取所有方法

			SharedPreferences sp = context.getSharedPreferences(
					config == null ? bean.getClass().getName() : config
							.getName(), Context.MODE_PRIVATE);

			final Editor editor = sp.edit();

			editor.clear().commit();

			Method[] methods = bean.getClass().getMethods();
			for (Method method : methods) {
				// 获取所有方法的名字 找到带有get开头的方法
				String methodName = method.getName();
				if (methodName.equals("getClass")) {
					continue;
				}
				if (methodName.startsWith("get")) {
					// 获取字段名
					final String fieldName = YBeanUtils
							.getFieldNameByMethodName(methodName);

					Object value = method.invoke(bean);

					Class<?> returnType = method.getReturnType();

					// if (value == null) {
					// editor.putString(fieldName, "null");
					// }

					if (returnType == String.class) {

						editor.putString(fieldName, (String) value);

					} else if (returnType == int.class
							|| returnType == Integer.class) {

						editor.putInt(fieldName, (Integer) value);

					} else if (returnType == float.class
							|| returnType == Float.class) {

						editor.putFloat(fieldName, (Float) value);

					} else if (returnType == long.class
							|| returnType == Long.class) {

						editor.putLong(fieldName, (Long) value);

					} else if (returnType == boolean.class
							|| returnType == Boolean.class) {
						editor.putBoolean(fieldName, (Boolean) value);
					}
				}
			}

			editor.commit();
		} catch (Exception e) {
			Yr.logError(e);
		}

	}

	/**
	 * 给我一个对象，我把它用SharedPreferences写到data/data里面
	 * 
	 * @param context
	 * @param bean
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	@SuppressLint("DefaultLocale")
	public static void storeBeanBySP1(Context context, Object bean) {

		// 健壮性
		if (bean == null) {
			throw new NullPointerException();
		}
		if (context == null) {
			throw new NullPointerException();
		}

		try {
			// 获取所有方法
			SharedPreferences sp = context.getSharedPreferences(bean.getClass()
					.getName(), Context.MODE_PRIVATE);

			final Editor editor = sp.edit();

			editor.clear().commit();

			Method[] methods = bean.getClass().getMethods();
			for (Method method : methods) {
				// 获取所有方法的名字 找到带有get开头的方法
				String methodName = method.getName();
				if (methodName.equals("getClass")) {
					continue;
				}
				if (methodName.startsWith("get")) {
					// 获取字段名
					final String fieldName = YBeanUtils
							.getFieldNameByMethodName(methodName);

					Object value = method.invoke(bean);

					if (value == null) {
						editor.putString(fieldName, "null");
					}

					Yr.d(fieldName + "=" + value);
					YBeanUtils.setOnTypeListener(value, new YBeanUtils.OnTypeListener() {

						@Override
						public void onString(String value) {

							editor.putString(fieldName, value);
						}

						@Override
						public void onLong(long value) {

							editor.putLong(fieldName, value);
						}

						@Override
						public void onInt(int value) {

							editor.putInt(fieldName, value);
						}

						@Override
						public void onFloat(float value) {

							editor.putFloat(fieldName, value);
						}

						@Override
						public void onBoolean(boolean value) {

							editor.putBoolean(fieldName, value);
						}

						@Override
						public void onDouble(double value) {

						}
					});
				}
			}

			Yr.d("成功");
			editor.commit();
		} catch (Exception e) {
			Yr.d("失败");
			Yr.logError(e);
		}

	}

	/**
	 * 通过SharedPreferences 把里面的数据读到javaBean里面
	 * 
	 * @param context
	 *            上下文对象
	 * @param beanClass
	 * @return
	 * @throws IllegalArgumentException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws UnsupportedEncodingException
	 */
	public static <T> T readBeanBySP(Context context, Class<T> beanClass) {

		T t = null;

		try {

			if (!hasSharedPreferences(context, beanClass.getName())) {

				return null;
			}

			t = beanClass.newInstance();

			final SharedPreferences sp = context.getSharedPreferences(
					beanClass.getName(), Context.MODE_PRIVATE);

			for (final Method method : beanClass.getDeclaredMethods()) {

				String methodName = method.getName();

				if (methodName.startsWith("set")) {

					final String fieldName = YBeanUtils
							.getFieldNameByMethodName(methodName);

					Field field = beanClass.getDeclaredField(fieldName);

					field.setAccessible(true);

					YBeanUtils.setOnTypeListener(t, field.getType(),
							new YBeanUtils.OnTypeListener1<T>() {

								@Override
								public void onInt(T t) {

									try {

										method.invoke(t,
												sp.getInt(fieldName, 0));

									} catch (Exception e) {
										Yr.logError(e);
									}
								}

								@Override
								public void onFloat(T t) {

									try {

										method.invoke(t,
												sp.getFloat(fieldName, 0));

									} catch (Exception e) {
										Yr.logError(e);
									}
								}

								@Override
								public void onString(T t) {

									try {

										method.invoke(t,
												sp.getString(fieldName, null));

									} catch (Exception e) {
										Yr.e(fieldName);
										Yr.logError(e);
									}
								}

								@Override
								public void onBoolean(T t) {

									try {

										method.invoke(t,
												sp.getBoolean(fieldName, false));

									} catch (Exception e) {
										Yr.logError(e);
									}
								}

								@Override
								public void onLong(T t) {
									try {
										method.invoke(t,
												sp.getLong(fieldName, 0));
									} catch (Exception e) {
										Yr.logError(e);
									}
								}

								@Override
								public void onDouble(T t) throws Exception {
									method.invoke(t,
											sp.getFloat(fieldName, 0));
								}
							});
				}
			}
			return t;
		} catch (Exception e) {
			Yr.e(e);
		}

		return null;
	}

	@SuppressLint("SdCardPath")
	private static boolean hasSharedPreferences(Context context, String name) {

		File file = new File("/data/data/" + context.getPackageName()
				+ "/shared_prefs", name + ".xml");

		Yr.e(file);
		if (file.exists()) {
			return true;
		}
		return false;
	}

	/**
	 * 从SharedPreferences里读取一条信息
	 * 
	 * @param context
	 *            上下文
	 * @param fileName
	 *            SP的文件名
	 * @param key
	 *            要获取那个值的key
	 * @return
	 */
	public static String readFromSP(Context context, String fileName, String key) {

		return context.getSharedPreferences(fileName, Context.MODE_PRIVATE)
				.getString(key, null);
	}

	public static void clear(Context context, String fileNmae) {

		SharedPreferences sp = context.getSharedPreferences(fileNmae,
				Context.MODE_PRIVATE);

		final Editor editor = sp.edit();

		editor.clear().commit();

	}

	public static interface Config {

		String getName();
	}
}
